package com.mini.cn.goods.dao;

import com.mini.cn.goods.common.PageQueryCallback;
import com.mini.cn.goods.common.PageQueryCondition;
import com.mini.cn.goods.common.PageQueryResult;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Created by fly on 17/5/16.
 */
@Repository("basedao")
@Slf4j
public class BaseDao<T> extends HibernateDaoSupport {

    @Autowired
    public void setSessionFactory0(SessionFactory sessionFactory){
        super.setSessionFactory(sessionFactory);
    }

    /**
     * 更新操作
     * @param t
     */
    public void update(T t) throws Exception{
        getHibernateTemplate().update(t);
    }

    /**
     * 删除操作
     * @param t
     */
    public void delete(T t) throws Exception{
        getHibernateTemplate().delete(t);
    }

    /**
     * 增加操作
     * @param t
     */
    public void save(T t) throws  Exception {
        getHibernateTemplate().save(t);
        //getHibernateTemplate().refresh(t);
    }

    /**
     * Used by the base DAO classes but here for your modification Get object
     * matching the given key and return it.
     */
    protected T get(Class refClass, Serializable key) {
        return (T) getHibernateTemplate().get(refClass, key);
    }

    protected List<T> loadAll(Class refClass){
        return getHibernateTemplate().loadAll(refClass);
    }

    /**
     * 查询返回较少对象的list，支持带where条件 带参数的查询
     * @param hql 如：from TblAppliBaseInfo t where t.appno='100'
     * @return list
     */
    public List find(String hql, Object values[]){
        return getHibernateTemplate().find(hql, values);
    }


    /**
     * 查询返回较少对象的list，支持带where条件
     * @param query 如：from TblAppliBaseInfo t where t.appno='100'
     * @return list
     */
    public List find(String query){
        return getHibernateTemplate().find(query);
    }

    /**
     * 根据分页查询条件查出分页查询结果
     *
     * @param queryCondition
     * @return
     * @throws Exception
     */
    public PageQueryResult pageQueryByHql(PageQueryCondition queryCondition) throws Exception {
        try {
            PageQueryCallback callback = new PageQueryCallback(queryCondition);
            PageQueryResult returnPageQueryResult = (PageQueryResult) getHibernateTemplate().execute(callback);
            return returnPageQueryResult;
        } catch (Exception e) {
            e.printStackTrace();
            new Exception("");
        }
        return null;
    }

    /**
     * 将查询回来的数据list（包含多个PO）转换成对应的VO
     *
     * @param <K>
     * @param queryResultList
     * @param k
     * @return
     */
    public <K> List<K> convertToVO(List queryResultList, Class<K> k) {
        Iterator iter = queryResultList.iterator();
        List<K> resultList = new ArrayList<K>();
        Method[] methods = k.getMethods();
        List<Method> setPoMethods = new ArrayList<Method>();
        boolean bFind;
        try {
            while (iter.hasNext()) {
                // 实例化目标对象
                K destDTO = k.newInstance();

                Object tempObj = iter.next();
                // 源对象取值
                Object[] obj;
                if (tempObj.getClass().isArray()) {
                    obj = (Object[]) tempObj;
                } else {
                    obj = new Object[1];
                    obj[0] = tempObj;
                }
                // 源对象取值
                // Object[] obj = (Object[])obj1;

                // 循环，将对应的po对象设置到K代表的destDTO里
                for (int i = 0; i < obj.length; i++) {
                    if (null != obj[i]) {
                        // 寻找到对应的方法，仅查找一次，记录到setPoMethods列表中。
                        if (setPoMethods.size() <= i) {// 第一次对应的方法没找过，需要找一下。
                            bFind = false;
                            for (Method method : methods) {
                                String name = method.getName();
                                if (name.startsWith("set")) {
                                    // 判断属性设置的参数是不是对应的obj类，并且是唯一的参数
                                    Class<?>[] paramClasses = method.getParameterTypes();
                                    // 有并且只要一个参数，并且这个参数类型为obj的类
                                    if ((paramClasses != null) && (paramClasses.length == 1)) {
                                        // 判断obj[i]的类型和参数类型一致。
                                        if (paramClasses[0].isInstance(obj[i])) {
                                            setPoMethods.add(method);
                                            bFind = true;
                                            break;
                                        }
                                    }
                                }
                            }
                            if (!bFind) {// 没找到，增加空指针，避免下次重复查找。
                                setPoMethods.add(null);
                                log.info("------" + obj[i].getClass().getName() + " 对应的po在DTO里没找到：");
                            }
                        }
                        // 将对应的对象设置到DTO内
                        if (setPoMethods.get(i) != null) {
                            // 将制定的对象设置到对应的DTO内属性
                            setPoMethods.get(i).invoke(destDTO, obj[i]);
                        }
                    }
                }
                // 填装List
                resultList.add(destDTO);
            }
        } catch (Exception e) {
            log.error("Exception", e);
            //log.info("------" + this.getClass().getName() + " commonQuery方法(每行返回多个po)遇到错误：" + e);
        }
        return resultList;
    }

    /**
     * 直接返回PageQueryResult
     *
     * @param hql
     * @param objArray
     * @param pageIndex
     * @param pageSize
     * @return
     * @throws Exception
     */
    public PageQueryResult commonQuery(String hql, Object objArray[], int pageIndex, int pageSize) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("------" + this.getClass().getName() + " commonQuery方法(每行返回x个po) 开始------");
            log.debug("------hql:" + hql);
        }
        long startTime = System.currentTimeMillis();
        PageQueryCondition queryCondition = new PageQueryCondition();
        queryCondition.setQueryString(hql);
        if (objArray != null) {
            queryCondition.setObjArray(objArray);
        }
        queryCondition.setPageIndex(pageIndex);
        queryCondition.setPageSize(pageSize);
        PageQueryResult pageQueryResult = pageQueryByHql(queryCondition);
        pageQueryResult.setPageIndex(pageIndex);
        pageQueryResult.setPageSize(pageSize);
        return pageQueryResult;
    }

    /**
     * 返回多个PO，自动将返回的多个PO注入到类K（DTO)里。如果K里没有注入对应方法，log出error。
     * @param <K>
     * @param hql
     * @param objArray
     * @param k
     * @return
     * @throws Exception
     */
    public <K> List<K> commonQuery(String hql,Object objArray[],Class<K> k ) throws Exception {
        if(log.isDebugEnabled()){
            log.debug("------"+this.getClass().getName()+" commonQuery方法(每行返回x个po) 开始------");
            log.debug("------hql:"+hql);
        }
        long startTime = System.currentTimeMillis();
        List queryResult;
        if(null != objArray && objArray.length > 0){
            queryResult = this.find(hql.toString(),objArray);
        }else{
            queryResult = this.find(hql.toString());
        }

        List<K> resultList;
        resultList=convertToVO(queryResult,k);
        if(log.isDebugEnabled()){
            long endTime = System.currentTimeMillis();
            log.debug("------"+this.getClass().getName()+" commonQuery方法(每行返回x个po)结束 ,共用时："+(float)(endTime-startTime)/1000+" 秒------");
        }
        return resultList;
    }

    /**
     * 返回多个PO，自动将返回的多个PO注入到类K（DTO)里。如果K里没有注入对应方法，log出error。
     *
     * @param <K>
     * @param hql
     * @param objArray
     * @param pageIndex
     * @param pageSize
     * @param k
     * @return
     * @throws Exception
     */
    public <K> PageQueryResult<K> commonQuery(String hql, Object objArray[], int pageIndex, int pageSize, Class<K> k)
            throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("------" + this.getClass().getName() + " commonQuery方法(每行返回x个po) 开始------");
            log.debug("------hql:" + hql);
        }
        long startTime = System.currentTimeMillis();
        PageQueryCondition queryCondition = new PageQueryCondition();
        queryCondition.setQueryString(hql);
        if (objArray != null) {
            queryCondition.setObjArray(objArray);
        }
        queryCondition.setPageIndex(pageIndex);
        queryCondition.setPageSize(pageSize);
        PageQueryResult pageQueryResult = pageQueryByHql(queryCondition);
        List<K> resultList;
        resultList = convertToVO(pageQueryResult.getQueryResult(), k);
        pageQueryResult.setPageIndex(pageIndex);
        pageQueryResult.setPageSize(pageSize);
        pageQueryResult.setQueryResult(resultList);
        if (log.isDebugEnabled()) {
            long endTime = System.currentTimeMillis();
            log.debug("------" + this.getClass().getName() + " commonQuery方法(每行返回x个po)结束 ,共用时："
                    + (float) (endTime - startTime) / 1000 + " 秒------");
        }
        return pageQueryResult;
    }

}
